package gateway

import (
	"azfirewall-gateway/firewall"
	"azfirewall-gateway/service"
	"azfirewall-gateway/utils"
	"context"
	"crypto/tls"
	"golang.org/x/net/http2"
	"net"
	"net/http"
	"net/http/httputil"
	"time"
)

var ccg = firewall.NewCCGroup()

// 定义全局CC组变量

func ReverseProxyHandler(w http.ResponseWriter, r *http.Request) {
	//根据域名查询数据库中的站点信息
	var site = service.GetSite(r.Host)
	//判断站点信息是否存在
	if site == nil {
		//站点信息不存在，返回错误
		utils.ProcessBlockResponse(w, utils.BlockedPage.InvalidDomainPage)
		return
	}
	//如果当前是http访问并且站点配置开启强制跳转https
	if r.TLS == nil && site.RedirectHttps {
		//强制跳转至https页面
		RedirectHTTPSFunc(w, r)
		return
	}

	if site.WAFEnabled {
		//TODO WAF策略检测
		cc, _ := ccg.LoadOrStore(r.Host, site.SiteCCPolicy)
		// 从全局CC组中取出站点的CC对象，若没有就创建一个新的对象
		if cc.IdentifyCCAttack(r, r.Host, utils.GetRealClientIP(r)) {
			utils.ProcessBlockResponse(w, utils.BlockedPage.CCAttackBlockPage)
			return
		}
	}
	r.URL.Scheme = site.InternalProtocol
	r.URL.Host = r.Host
	var origin = site.SourceSite.IP + ":" + site.SourceSite.Port
	//utils.MainLog.Info("代理地址：" + origin)
	trans := &http.Transport{
		TLSHandshakeTimeout:   10 * time.Second,
		IdleConnTimeout:       30 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
		DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
			return net.Dial("tcp", origin)
		},
		DialTLS: func(network, addr string) (net.Conn, error) {
			conn, err := net.Dial("tcp", origin)
			if err != nil {
				return nil, err
			}
			cfg := &tls.Config{ServerName: r.Host, NextProtos: []string{"h2", "http/1.1"}}
			tlsConn := tls.Client(conn, cfg)
			if err := tlsConn.Handshake(); err != nil {
				_ = conn.Close()
				return nil, err
			}
			return tlsConn, nil
		},
	}
	_ = http2.ConfigureTransport(trans)
	proxy := &httputil.ReverseProxy{
		Director: func(req *http.Request) {
			req.URL.Scheme = site.InternalProtocol
			req.URL.Host = r.Host
		},
		Transport:      trans,
		ModifyResponse: rewriteResponse}
	//if utils.Debug {
	//	dump, err := httputil.DumpRequest(r, true)
	//	utils.CheckError("ReverseHandlerFunc DumpRequest", err)
	//	fmt.Println(string(dump))
	//}
	proxy.ServeHTTP(w, r)
}

func RedirectHTTPSFunc(w http.ResponseWriter, r *http.Request) {
	target := "https://" + r.Host + r.URL.Path
	if len(r.URL.RawQuery) > 0 {
		target += "?" + r.URL.RawQuery
	}
	http.Redirect(w, r, target, http.StatusMovedPermanently)
}
